#pragma once

#include <string>
#include <string_view>
#include <atomic>
#include <chrono>

using namespace std::chrono_literals;


struct TestSetBase;
struct BenchmarkWorkloadBase {
    /** the human-readable name of the test case */
    const std::string name;
    /** parallelism of this test case */
    const unsigned thread_nr;

    const unsigned long long minimum_runs;
    const std::chrono::seconds minimum_time;
    /** how many times the workload has been executed */
    std::atomic<unsigned long long> executed_times;
    std::chrono::nanoseconds executed_timespan;

    /**
     * @param name name of the test case
     * @param thread_nr number of parallel workers
     * @param minimum_runs minimum total number of workload issues
     */
    explicit BenchmarkWorkloadBase(
            const std::string_view name, unsigned thread_nr,
            unsigned long long minimum_runs)
        : name(name), thread_nr(thread_nr),
            minimum_runs(minimum_runs), minimum_time(5s - 0s),
            executed_times(0)
    { }

    /**
     * 
     * @param testctx belonging test set, used for passing context
     */
    virtual void init(TestSetBase *testctx) const = 0;
    /**
     * instantiation of this class should fill this with actual work done via
     * invoking Objecter::op_submit()
     * @param testctx belonging test set, used for passing context
     * @param thread_id the ID of the worker invoking this run of the workload
     * @param seed a seed used to generate distinct oid
     */
    virtual void workload(TestSetBase *testctx, unsigned thread_id, uint64_t seed) const = 0;
    /**
     * @note implementation is expected to be idempotent
     * @param testctx belonging test set, used for passing context
     */
    virtual void cleanup(TestSetBase *testctx) const = 0;

    /**
     * run workload in parallel
     *
     * executed_times and executed_timespan will be concluded after this
     * function returns
     * 
     * @param testctx belonging test set, used for passing context
     */
    void operator()(TestSetBase *testctx);
};  /* struct BenchmarkWorkloadBase */
